package net.xdclass.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import lombok.extern.slf4j.Slf4j;
import net.xdclass.config.PayConstant;
import net.xdclass.config.RabbitMQConfig;
import net.xdclass.controller.request.wx.NativeOrderRequest;
import net.xdclass.enums.PayOrderType;
import net.xdclass.manager.WxPayManager;
import net.xdclass.mapper.WxOrderInfoMapper;
import net.xdclass.mapper.WxOrderStatusMapper;
import net.xdclass.model.WxOrderInfoDO;
import net.xdclass.model.WxOrderStatusDO;
import net.xdclass.model.message.NativeOrderRequestMessage;
import net.xdclass.model.message.PayOrderStatusEventMessage;
import net.xdclass.service.WxPayService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.HashMap;
import java.util.Map;

/**
 * @author Administrator
 * @description
 * @since 2023-07-02 22:09
 */
@Service
@Slf4j
public class WxPayServiceImpl implements WxPayService {

    @Autowired
    WxPayManager wxPayManager;

    @Autowired
    private RabbitTemplate rabbitTemplate;

    @Autowired
    private RabbitMQConfig rabbitMQConfig;

    @Autowired
    private WxOrderInfoMapper wxOrderInfoMapper;

    DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");

    @Transactional
    @Override
    public Map<String, Object> insertPrepareOrder(NativeOrderRequest nativeOrderRequest) {

        if (StringUtils.isEmpty(nativeOrderRequest.getTime_expire())) {
            LocalDateTime nowTime = LocalDateTime.now();
            nativeOrderRequest.setTime_expire(nowTime.format(formatter));
        }

        if (nativeOrderRequest.getSupport_fapiao() == null) {
            nativeOrderRequest.setSupport_fapiao(false);
        }

        WxOrderInfoDO orderInfoDO = WxOrderInfoDO.builder()
                .appid(nativeOrderRequest.getAppid())
                .mchid(nativeOrderRequest.getMchid())
                .description(nativeOrderRequest.getDescription())
                .outTradeNo(nativeOrderRequest.getOut_trade_no())
                .timeExpire(LocalDateTime.parse(nativeOrderRequest.getTime_expire(), formatter))
                .attach(nativeOrderRequest.getAttach())
                .goodsTag(nativeOrderRequest.getGoods_tag())
                .supportFapiao(nativeOrderRequest.getSupport_fapiao() ? 1 : 0)
                .total(nativeOrderRequest.getAmount().getTotal())
                .currency(nativeOrderRequest.getAmount().getCurrency())
                .notifyUrl(nativeOrderRequest.getNotify_url())
                .build();

        Integer orderRows = wxPayManager.insertPrepareOrder(orderInfoDO);
        log.info("插入订单行数: {}", orderRows);

        WxOrderStatusDO orderStatus = WxOrderStatusDO.builder()
                .orderId(orderInfoDO.getId())
                .orderStatus(PayOrderType.PREPARE.name())
                .build();
        Integer orderStatusRows = wxPayManager.insertOrderStatus(orderStatus);
        log.info("插入订单状态行数: {}", orderStatusRows);


        // 发送mq延迟消息
        PayOrderStatusEventMessage eventMessage = new PayOrderStatusEventMessage();
        eventMessage.setMchid(nativeOrderRequest.getMchid());
        eventMessage.setOutTradeNo(nativeOrderRequest.getOut_trade_no());
        eventMessage.setOrderId(orderStatus.getOrderId());
        log.info("发送延迟消息: exchange: {}, routingKey: {}, message: {}", rabbitMQConfig.getPayEventExchange(),
                rabbitMQConfig.getPayOrderStatusRoutingKey(), eventMessage);
        rabbitTemplate.convertAndSend(rabbitMQConfig.getPayEventExchange(),
                rabbitMQConfig.getPayOrderStatusRoutingKey(), eventMessage);

        // 组合支付 URL
        WxOrderInfoDO wxOrderInfoDO = wxOrderInfoMapper.selectOne(new QueryWrapper<WxOrderInfoDO>()
                .eq("out_trade_no", nativeOrderRequest.getOut_trade_no()));
        Map<String, Object> resultData = new HashMap<>();
        resultData.put("pay_url", PayConstant.PAY_BASE_URL + "/wechat/v3/pay/transactions/pay?orderId=" + wxOrderInfoDO.getId());

        return resultData;
    }

    @Override
    public String queryOrderStatusByOutTradeNo(String outTradeNo, String merid) {
        return wxPayManager.queryOrderStatusByOutTradeNo(outTradeNo, merid);
    }

    @Override
    public Boolean changeOrderStatusByOutTradeNo(String outTradeNo, String merid,
                                                 PayOrderType oldStatus, PayOrderType newStatus) {

        return wxPayManager.changeOrderStatusByOutTradeNo(outTradeNo, merid, oldStatus, newStatus);
    }

    @Override
    public Boolean changeOrderStatusByOrderId(Long orderId, PayOrderType oldStatus, PayOrderType newStatus) {
        return wxPayManager.changeOrderStatusByOrderId(orderId, oldStatus, newStatus);
    }

    /**
     * 支付接口
     *
     * @param orderId
     * @return
     */
    @Override
    public Boolean payByOrderId(Long orderId) {
        WxOrderInfoDO wxOrderInfoDO = wxOrderInfoMapper.selectOne(new QueryWrapper<WxOrderInfoDO>()
                .eq("id", orderId)
                .last("limit 1"));
        if (wxOrderInfoDO == null) {
            log.error("未找到该订单: {}", orderId);
            return false;
        }

        Boolean payResult = changeOrderStatusByOrderId(orderId, PayOrderType.PREPARE, PayOrderType.FINISH);

        // 异步通知支付成功结果
        notifyPayResult(wxOrderInfoDO);

        return payResult;
    }

    /**
     * 支付成功，发送支付结果通知 mq
     * @param WxOrderInfoDO
     */
    public void notifyPayResult(WxOrderInfoDO WxOrderInfoDO) {

        NativeOrderRequestMessage eventMessage = new NativeOrderRequestMessage();
        eventMessage.setMchid(WxOrderInfoDO.getMchid());
        eventMessage.setOutTradeNo(WxOrderInfoDO.getOutTradeNo());
        eventMessage.setNotifyUrl(WxOrderInfoDO.getNotifyUrl());
        eventMessage.setOrderStatus(PayOrderType.FINISH.name());
        eventMessage.setAttach(WxOrderInfoDO.getAttach());

        rabbitTemplate.convertAndSend(rabbitMQConfig.getPayEventExchange(),
                rabbitMQConfig.getPayResultNotifyRoutingKey(),
                eventMessage);
    }
}
